package com.sky.interceptor;

import com.sky.constant.JwtClaimsConstant;
import com.sky.context.ThreadLocalContext;
import com.sky.properties.JwtProperties;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 定义一个拦截用户端请求的拦截器,以"/user/**"为匹配路径,并在请求头中携带token信息
 * @author sky
 * @create 2021-09-16 14:59
 */
@Component//拦截器对象要被Spring容器管理
public class JwtTokenUserInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(JwtTokenUserInterceptor.class);
    @Autowired
    private JwtProperties jwtProperties;// 注入jwt配置类
    // 在请求处理之前执行的方法，用于预处理请求-->访问controller之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //HttpServletRequest是请求对象，HttpServletResponse是响应对象，Object handler是处理器对象，返回值是布尔值，true表示继续请求，false表示中断请求\
        if (!(handler instanceof HandlerMethod)) {
            return true;
            //处理请求的处理器不是控制器方法，直接返回true
            //可能是静态资源，直接返回true
        }

        //从请求头中获取token中的jwt令牌
        String authorizationJwt = request.getHeader(jwtProperties.getUserTokenName());
        log.info("从请求头中获取的token为:{}", authorizationJwt);
        //进行jwt令牌的校验
        //1.判断jwt令牌是否为空
        if (authorizationJwt == null || authorizationJwt.isEmpty()) {
            //返回统一的错误信息
            response.sendError(401, "请先登录");
            return false;
        }
        //2.判断jwt令牌是否有效
        try {
            log.info("开始校验jwt令牌");
            Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), authorizationJwt);//解析jwt令牌,获取有效载荷中的用户信息
            log.info("jwt令牌校验成功");
            //获取登入用户的ID存放在threadLocal线程局部变量中
            Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());//获取用户ID,转换为Long类型
            log.info("当前登入用户的ID为:{}", userId);
            ThreadLocalContext.setCurrentLocalUserId(userId);//设置当前线程的用户ID
            return true;//返回true表示继续请求
        } catch (Exception e) {
            response.sendError(401, "jwt令牌无效");
            return false;//返回false表示中断请求
        }
    }

    // 在请求处理之后执行的方法，用于后处理请求-->访问controller之后
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    // 在整个请求结束之后执行的方法，用于清理资源-->请求处理之后
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }

}
